/*
 * Jenny Ruppen 09-730-391
 * Sebastien Goldberg 08-914-855
 * Henry Raymond 08-928-061
 * Stefan Mussato 09-752-270
 */
 
package ch.uzh.ifi.sopra.gruppe9.game;

import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;


/**
 * Controls text input through the keyboard.
 */
public class TextInput {
	
	
	// variable introduced in order to avoid SONAR Major error "avoid duplicate literals", stefan
	private static final String textInputShift = "TextInputShift";
	private static final String textInputBackspace = "TextInputBackspace";
	private static final String textInputDelete = "TextInputDelete";
	private static final String textInputLeft = "TextInputLeft";
	private static final String textInputRight = "TextInputRight";
	private static final String textInputEnter = "TextInputEnter";
	private static final String textInput_ = "TextInput_";
	
	
	
	/**
	 * Private class to easily save all needed keys.
	 */
	private static class TextInputKey {
		public String value;
		public int key;
		
		public TextInputKey(String value, int key) {
			this.value = value;
			this.key = key;
		}
	}
	
	
	/**
	 * All keys that will be mapped.
	 */
	private static final TextInputKey[] allKeys = {
		
		new TextInputKey("A", KeyInput.KEY_A),
		new TextInputKey("B", KeyInput.KEY_B),
		new TextInputKey("C", KeyInput.KEY_C),
		new TextInputKey("D", KeyInput.KEY_D),
		new TextInputKey("E", KeyInput.KEY_E),
		new TextInputKey("F", KeyInput.KEY_F),
		new TextInputKey("G", KeyInput.KEY_G),
		new TextInputKey("H", KeyInput.KEY_H),
		new TextInputKey("I", KeyInput.KEY_I),
		new TextInputKey("J", KeyInput.KEY_J),
		new TextInputKey("K", KeyInput.KEY_K),
		new TextInputKey("L", KeyInput.KEY_L),
		new TextInputKey("M", KeyInput.KEY_M),
		new TextInputKey("N", KeyInput.KEY_N),
		new TextInputKey("O", KeyInput.KEY_O),
		new TextInputKey("P", KeyInput.KEY_P),
		new TextInputKey("Q", KeyInput.KEY_Q),
		new TextInputKey("R", KeyInput.KEY_R),
		new TextInputKey("S", KeyInput.KEY_S),
		new TextInputKey("T", KeyInput.KEY_T),
		new TextInputKey("U", KeyInput.KEY_U),
		new TextInputKey("V", KeyInput.KEY_V),
		new TextInputKey("W", KeyInput.KEY_W),
		new TextInputKey("X", KeyInput.KEY_X),
		new TextInputKey("Y", KeyInput.KEY_Y),
		new TextInputKey("Z", KeyInput.KEY_Z),
		
		new TextInputKey("1", KeyInput.KEY_1),
		new TextInputKey("2", KeyInput.KEY_2),
		new TextInputKey("3", KeyInput.KEY_3),
		new TextInputKey("4", KeyInput.KEY_4),
		new TextInputKey("5", KeyInput.KEY_5),
		new TextInputKey("6", KeyInput.KEY_6),
		new TextInputKey("7", KeyInput.KEY_7),
		new TextInputKey("8", KeyInput.KEY_8),
		new TextInputKey("9", KeyInput.KEY_9),
		new TextInputKey("0", KeyInput.KEY_0),
		
		new TextInputKey("1", KeyInput.KEY_NUMPAD1),
		new TextInputKey("2", KeyInput.KEY_NUMPAD2),
		new TextInputKey("3", KeyInput.KEY_NUMPAD3),
		new TextInputKey("4", KeyInput.KEY_NUMPAD4),
		new TextInputKey("5", KeyInput.KEY_NUMPAD5),
		new TextInputKey("6", KeyInput.KEY_NUMPAD6),
		new TextInputKey("7", KeyInput.KEY_NUMPAD7),
		new TextInputKey("8", KeyInput.KEY_NUMPAD8),
		new TextInputKey("9", KeyInput.KEY_NUMPAD9),
		new TextInputKey("0", KeyInput.KEY_NUMPAD0),
		
		new TextInputKey(" ", KeyInput.KEY_SPACE),
		new TextInputKey(",", KeyInput.KEY_COMMA),
		new TextInputKey(";", KeyInput.KEY_SEMICOLON),
		new TextInputKey(".", KeyInput.KEY_PERIOD),
		new TextInputKey(":", KeyInput.KEY_COLON),
		new TextInputKey("-", KeyInput.KEY_MINUS),
		new TextInputKey("_", KeyInput.KEY_UNDERLINE),
		new TextInputKey("/", KeyInput.KEY_SLASH),
		
		new TextInputKey(".", KeyInput.KEY_DECIMAL),
		new TextInputKey("/", KeyInput.KEY_DIVIDE)
		
	};
	
	
	/**
	 * If the shift key is pressed or not. (upper or lowercase)
	 */
	private static boolean shiftPressed = false;
	
	
	/**
	 * True if the text input is currently active.
	 */
	private static boolean active = false;
	
	
	/**
	 * Listener for all characters that can be typed.
	 */
	private static ActionListener characterListener;
	
	
	/**
	 * Listener for all controls used to interact with text input.
	 */
	private static ActionListener controlListener;
	
	
	/**
	 * String which is entered.
	 */
	private static String string;
	
	
	/**
	 * Cursor position.
	 */
	private static int cursorPosition;
	
	
	/**
	 * Repeat character timer.
	 */
	private static float repeatTimer;
	
	
	/**
	 * Repeat action.
	 */
	private static String repeatAction;
	
	
	/**
	 * Input Manager of jME3
	 */
	private static InputManager inputManager;
	
	
	/**
	 * True if enter key has been pressed.
	 */
	private static boolean enterPressed;
	
	
	/**
	 * Setup text input.
	 */
	public static void setup(InputManager newInputManager) {
		
		inputManager = newInputManager;
		
		repeatTimer = 0.0f;
		repeatAction = "";
		
		characterListener = new ActionListener() {
			public void onAction(String name, boolean keyPressed, float tpf) {
				repeatTimer = 0.0f;
			    if(keyPressed) {
			    	String key;
			    	if(shiftPressed) {
			    		key = name.substring(10);
			    	} else {
			    		key = name.substring(10).toLowerCase();
			    	}
		    		string = string.substring(0, cursorPosition) + key + string.substring(cursorPosition);
		    		cursorPosition++;
			    	repeatAction = "TextInputCharacter";
			    } else {
			    	repeatAction = "";
			    }
			}
		};
		
		controlListener = new ActionListener() {
			public void onAction(String name, boolean keyPressed, float tpf) {
				repeatTimer = 0.0f;
			    if(!keyPressed) {
			    	if(name.equals(textInputShift)) {
			    		shiftPressed = false;
			    	}
			    	repeatAction = "";
			    	
			    } else {
			    	if(name.equals(textInputBackspace) && (cursorPosition >= 1)) {
			    		string = string.substring(0, cursorPosition - 1) + string.substring(cursorPosition);
			    		cursorPosition--;
			    		repeatAction = textInputBackspace;
			    	}
			    	if(name.equals(textInputDelete) && (cursorPosition < string.length())) {
			    		string = string.substring(0, cursorPosition) + string.substring(cursorPosition + 1);
			    		repeatAction = textInputDelete;
			    	}
			    	if(name.equals(textInputLeft) && (cursorPosition >= 1))
			    		cursorPosition--;
			    		repeatAction = textInputLeft;
			    	}
			    	if(name.equals(textInputRight) && (cursorPosition < string.length())) {
			    		cursorPosition++;
			    		repeatAction = textInputRight;
			    	}
			    	if(name.equals(textInputShift)) {
			    		shiftPressed = true;
			    		repeatAction = "";
			    	}
			    	if(name.equals(textInputEnter)) {
			    		enterPressed = true;
			    		repeatAction = "";
			    	}
			    }
		};

	}
	
	
	/**
	 * Start text input.
	 */
	public static void start(String initialString) {
		active = true;
		string = initialString;
		cursorPosition = initialString.length();
		enterPressed = false;
		String[] mappings = new String[allKeys.length];
		for(int i = 0; i < allKeys.length; i++) {
			inputManager.addMapping(textInput_.concat(allKeys[i].value), new KeyTrigger(allKeys[i].key));
			mappings[i] = textInput_.concat(allKeys[i].value);
		}
		
		inputManager.addMapping(textInputShift, new KeyTrigger(KeyInput.KEY_LSHIFT), new KeyTrigger(KeyInput.KEY_RSHIFT));
		inputManager.addMapping(textInputBackspace, new KeyTrigger(KeyInput.KEY_BACK));
		inputManager.addMapping(textInputDelete, new KeyTrigger(KeyInput.KEY_DELETE));
		inputManager.addMapping(textInputLeft, new KeyTrigger(KeyInput.KEY_LEFT));
		inputManager.addMapping(textInputRight, new KeyTrigger(KeyInput.KEY_RIGHT));
		inputManager.addMapping(textInputEnter, new KeyTrigger(KeyInput.KEY_RETURN));
		
		inputManager.addListener(characterListener, mappings);
		
		inputManager.addListener(controlListener, new String[] {textInputShift, textInputBackspace, textInputDelete, textInputLeft, textInputRight, textInputEnter});

	}
	
	
	/**
	 * End text input.
	 */
	public static void end() {
		active = false;
		for(int i = 0; i < allKeys.length; i++) {
			if(inputManager.hasMapping(textInput_.concat(allKeys[i].value))) {
				inputManager.deleteMapping(textInput_.concat(allKeys[i].value));
			}
		}
		
		inputManager.deleteMapping(textInputShift);
		inputManager.deleteMapping(textInputBackspace);
		inputManager.deleteMapping(textInputDelete);
		inputManager.deleteMapping(textInputLeft);
		inputManager.deleteMapping(textInputRight);
		inputManager.deleteMapping(textInputEnter);
		
		inputManager.removeListener(characterListener);
		
		inputManager.removeListener(controlListener);

	}


	public static String getString() {
		return string;
	}


	public static int getCursorPosition() {
		return cursorPosition;
	}


	public static void update(float delta) {
		if(active) {
			repeatTimer += delta;
			while(repeatTimer >= 0.55f) {
				repeatTimer -= 0.05f;
				
				if(repeatAction.equals("TextInputCharacter")) {
					String key;
			    	if(shiftPressed) {
			    		key = string.substring(cursorPosition - 1, cursorPosition);
			    	} else {
			    		key = string.substring(cursorPosition - 1, cursorPosition).toLowerCase();
			    	}
					string = string.substring(0, cursorPosition) + key + string.substring(cursorPosition);
					cursorPosition++;
				
				} else if(repeatAction.equals(textInputBackspace)) {
					if(cursorPosition >= 1) {
		    			string = string.substring(0, cursorPosition - 1) + string.substring(cursorPosition);
		    			cursorPosition--;
		    		}
					
				} else if(repeatAction.equals(textInputDelete)) {
		    		if(cursorPosition < string.length()) {
		    			string = string.substring(0, cursorPosition) + string.substring(cursorPosition + 1);
		    		}
					
				} else if(repeatAction.equals(textInputLeft)) {
		    		if(cursorPosition >= 1) {
		    			cursorPosition--;
		    		}
					
				} else if(repeatAction.equals(textInputRight)) {
		    		if(cursorPosition < string.length()) {
		    			cursorPosition++;
		    		}
				}
			}
		}
	}
	
	
	/**
	 * Returns if the enter key has just been pressed, and if so, resets the value to false.
	 */
	public static boolean hasEnterKeyBeenPressed() {
		boolean currentEnterPressed = enterPressed;
		enterPressed = false;
		return currentEnterPressed;
	}


	public static void setCursorPosition(int newCursorPositon) {
		cursorPosition = newCursorPositon;
	}
	
	
	public static void setString(String newString) {
		string = newString;
		if(cursorPosition > string.length()) {
			cursorPosition = string.length();
		}
	}
	
}
